package com.itqf.controller;

import cn.dsna.util.images.ValidateCode;
import com.itqf.annotation.JSONType;
import com.itqf.captcha.CaptchaManager;
import com.itqf.pojo.User;
import com.itqf.service.UserService;
import com.itqf.service.impl.UserServiceImpl;
import com.itqf.utils.Constants;
import com.itqf.utils.StrUtils;
import com.itqf.vo.R;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.sql.SQLException;
import java.util.Map;
import java.util.UUID;

/**
 * projectName: gpshop
 *
 * @author: 赵伟风
 * time: 2021/7/20 14:49
 * description:用户模块对应的controller
 *      账号检查
 *      用户注册
 *      用户激活
 *      用户登录
 *      用户退出登录
 */
@WebServlet("/user/*")
public class UserController  extends  BaseServlet{


    /**
     * 检查用户是否存在!
     *
     * baseServlet
     *    string 转发 forward: /重定向 redirect:
     *    字节文件  void
     *    json     R
     *
     *  controller
     *     1.接受判断账号
     *     2.调用service R
     *     3.响应数据
     *  service
     *     1.判断账号是否为null
     *     2. long count(1) 数据库查询
     *     3. 判断结果封装R
     *  dao
     *     数据库查询  根据用户名使用count聚合函数
     *
     * @param request  uAccount
     * @param response
     * @return
     */
    @JSONType
    public R check(HttpServletRequest request, HttpServletResponse response) throws SQLException {

        //获取要检验的账号
        String uAccount = request.getParameter("uAccount");

        //调用service
        UserService userService = new UserServiceImpl();
        R r = userService.checkAccount(uAccount);

        //返回r即可
        return r;
    }


    /**
     * 注册接口
     *    接受前端传递的用户数据!
     *    后台进行保存!
     *    注意:可能失败! 失败原因 第一 账号已经注册 第二 用户的参数为null
     * @param request
     * @param response
     * @return
     */
    public String register(HttpServletRequest request,HttpServletResponse response) throws InvocationTargetException, IllegalAccessException, SQLException {
        //1.接收参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        User user = new User();
        BeanUtils.populate(user, parameterMap);

        //2.调用业务方法
        UserService userService = new UserServiceImpl();
        R r =  userService.register(user);

        //3.返回结果
        if (r.getCode() == 0)
        {
            //注册失败
            request.setAttribute("msg",r.getMsg());
            return Constants.FORWARD_ACTION + "/register.jsp";
        }

        request.setAttribute("msg", r.getMsg());

        return Constants.FORWARD_ACTION + "/login.jsp";
    }


    /**
     * 激活成功
     *  u_state = 1
     *  u_token = null
     * 激活失败
     *  已经被激活
     *
     * @param request
     * @param response
     * @return
     */
    public String activate(HttpServletRequest request,HttpServletResponse response) throws SQLException {


        //1.获取请求参数
        String token = request.getParameter("c");

        //2.调用业务逻辑
        UserService userService = new UserServiceImpl();
        R r = userService.active(token);
        //3.返回结果

        if (r.getCode() == 0) {
            //激活失败
            request.setAttribute("msg", r.getMsg());
            //提示页面
            return Constants.FORWARD_ACTION + "/message.jsp";
        }

        request.setAttribute("msg", r.getMsg());

      return Constants.FORWARD_ACTION + "/login.jsp";
    }


    /**
     *
     * 验证码接口! 返回验证码还的将验证码装到CaptchaManager!
     *
     * 1.获取账号信息
     * 2.调用service R
     *     1.判断账号和密码以及验证码是否为null - fail
     *     2.判断验证码是否正确 fail
     *     3.密码 md5处理 有盐
     *     4.查询账号和密码查询用户 数据查询 dao
     *     5.user == null 账号或者密码错误!
     *     6.user != null user state = 0 账号未激活! fail
     *     7.成功 ok
     *
     * 3.R判断页面跳转
     *     1. R.code == 1 成功 user - session -- 程序的首页! index.jsp页面! --- 注意首页的显示! 显示账号信息!
     *
     *        自动登录保存: 判断勾选了自动登录! != null!
     *                     将账号和密码信息存储到cookie!  cookie的有效时间! setMaxAge(60*60*24*7) user
     *                                                  cookie.setPath(/项目根路径);
     *
                                cookie自动登录的校验信息存储问题:
                                    1.加密[带秘钥的加密]
                                                   加密存储
                                                   加密的方式:
                                                        md5 sha1 转码方式! 不可逆转! 可以做密码的处理!
                                                        base64 转码范式! 可以逆转! 防止乱码!用字符串的形式存字节文件!

                                                        加密的方式:
                                                            对称型加密: 加密和解密同一把秘钥! AES/DES:
                                                            非对称型加密: RSA 1024 RSA2 2048 16 2048

                                    2.存储唯一标识 账号的唯一标识等同于账号和密码 但是不同方式认证的!
                                                  账号和密码是登录页面人为认证!
                                                  唯一标识代码校验!
                                                  可以随意更换,并不会影响用户登录!
                                                  唯一标识token没有特定的要求,只需要不重复即可!uuid!

                           判断没有勾线!取消自动登录 == null
                           将账号和密码信息存储到cookie!  cookie的有效时间! setMaxAge(-1)
     *                                                  cookie.setPath(/项目根路径);
     *
     *     2. R.code == 0 失败 request msg = R.msg   --->  login.jsp
     *
     *
     *
     * 自定登录的过滤器:
     *    AutoLoginFilter
     *    /login.jsp
     *
     *    1.判断是否有存储存储账号密码的cookie user
     *    2.没有 cookie 放行  -- login.jsp
     *    3.有 cookie
     *      1.获取账号和密码
     *      2.查询数据库校验
     *      3.校验不同过 --  放行
     *      4.校验通过
     *          查询user
     *          user存储到session
     *          跳转到index.jsp页面!

     * @param request
     * @param response
     * @return
     * @throws SQLException
     */
    public String login(HttpServletRequest request,HttpServletResponse response) throws SQLException {

        Map<String, String[]> map = request.getParameterMap();

        //调用业务进行登录
        UserService userService = new UserServiceImpl();
        R r = userService.login(map);


        if (r.getCode() == 0) {
            request.setAttribute("msg", r.getMsg());
            return Constants.FORWARD_ACTION + "/login.jsp";
        }


        User user = (User) r.getData();

        Cookie cookie = null;
        //登录成功
        if (map.containsKey("auto") && !StrUtils.isEmpty(map.get("auto")[0])) {
            //勾选了自动登录
            //账号和密码存储到cookie中
            //token
            String token = UUID.randomUUID().toString().replaceAll("-", "");
            //将token标识存到用户表中
            userService.addToken(user.getuId(),token);
            cookie = new Cookie("token", token);
            cookie.setMaxAge(7*24*60*60);
            cookie.setPath(request.getContextPath());
        }else{
            //覆盖本地的cookie
            cookie = new Cookie("token", "");
            cookie.setMaxAge(0);
            cookie.setPath(request.getContextPath());
        }

        response.addCookie(cookie);

        HttpSession session = request.getSession();

        session.setAttribute("user", user);

        /**
         *
         * 转发和重定向的区别?
         * 转发和重定向的使用场景!
         *   转发一个模块内的资源跳转!
         *   重定向跨模块资源跳转!
         */

        return Constants.REDIRECT_ACTION + request.getContextPath()+"/index.jsp";
    }


    /**
     * 生成验证码图片
     * @param request
     * @param response
     * @return
     * @throws SQLException
     */
    public void code(HttpServletRequest request,HttpServletResponse response) throws SQLException, IOException {

        ValidateCode code = new ValidateCode(110, 60, 1, 4);

        String captcha = code.getCode();

        boolean is = CaptchaManager.addToCache(captcha, null);

        if (!is){
            //验证码存储失败
            ValidateCode tcode = new ValidateCode(60, 30, 1, 4);
            String tcaptcha = code.getCode();
            CaptchaManager.addToCache(tcaptcha, null);

            tcode.write(response.getOutputStream());
        }else{

            code.write(response.getOutputStream());
        }

    }

}
